package com.ruoyi.project.module.api.auth.wechat.service;

import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.project.module.api.auth.wechat.utils.WeChatConstant;
import com.ruoyi.project.module.api.utils.RedisUtil;
import com.ruoyi.project.module.api.utils.JwtUtils;
import com.ruoyi.project.module.member.domain.Member;
import com.ruoyi.project.module.member.service.impl.MemberServicePlusImpl;
import com.ruoyi.project.system.config.service.IConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

@Service
public class WeChatAuthService {

    private String appId = "";

    private String appSecret = "";

    @Autowired
    private IConfigService configService;

    @Autowired
    private MemberServicePlusImpl memberService;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisUtil redisUtil;


    public void getAppIdAndAppSecret() {
        appId = configService.selectConfigByKey("auth.wechat.appID");
        appSecret = configService.selectConfigByKey("auth.wechat.appsecret");
    }

    /**
     * 从微信公众号获取access_token
     * @return
     */
    public String getAccessTokenFromWeChat() {
        getAppIdAndAppSecret();
        String url = String.format(WeChatConstant.GET_ACCESS_TOKEN, appId, appSecret);
        String result = HttpRequest.get(url).execute().body();
        JSONObject object = JSONUtil.parseObj(result);
        StaticLog.info(object.toString(), "INFO");
        String accessToken = (String) object.get("access_token");
        Integer expiresIn = (Integer) object.get("expires_in");
        redisUtil.set(WeChatConstant.REDIS_KEY_ACCESS_TOKEN, accessToken, expiresIn);
        return accessToken;
    }

    /**
     * 从redis缓存中获取access_token
     * @return
     */
    public String getAccessTokenFromRedis() {
        String accessToken = (String) redisUtil.get(WeChatConstant.REDIS_KEY_ACCESS_TOKEN);
        if (StringUtils.isNotNull(accessToken)) {
            return accessToken;
        }
        return getAccessTokenFromWeChat();
    }

    /**
     * 通过openId获得用户信息
     * @param openId
     * @return
     */
    public JSONObject getUserInfoByOpenId(String openId) {
        String token = getAccessTokenFromRedis();
        String url = String.format(WeChatConstant.GET_USER_INFO, token, openId);
        String result = HttpRequest.get(url).execute().body();
        JSONObject object = JSONUtil.parseObj(result);
        return object;
    }

    /**
     * 创建登录二维码
     * @param sceneStr
     * @return
     */
    public Map<String, Object> createQrCode(String sceneStr) {
        String token = getAccessTokenFromRedis();
        // 获得二维码ticket
        String url = String.format(WeChatConstant.GET_QRCODE_TICKET, token);
        // 创建data
        if (StringUtils.isBlank(sceneStr)) {
            sceneStr = WeChatConstant.REDIS_KEY_WECHAT_QRCODE_PREFIX + IdUtil.simpleUUID();
        }
        String data = String.format(WeChatConstant.QRCODE_FORM_DATA, WeChatConstant.EXPIRE_SECONDS, sceneStr);
        String result = HttpRequest.post(url).body(data).execute().body();
        JSONObject object = JSONUtil.parseObj(result);
        StaticLog.info(object.toString(), "INFO");
        String ticket = (String) object.get("ticket");
        String code = String.format(WeChatConstant.SHOW_QRCODE, ticket);
        long expires = System.currentTimeMillis() / 1000 + WeChatConstant.EXPIRE_SECONDS;
        Map<String, Object> map = new HashMap<>();
        map.put("qr_code", code);
        map.put("sceneStr", sceneStr);
        map.put("expires", expires);
        StaticLog.info(map.toString(), "INFO");
        // 在Redis设置一个值为空的键值对，在登录成功后填入对应的用户的openId
        redisUtil.set(sceneStr, "", WeChatConstant.EXPIRE_SECONDS);
        return map;
    }

    /**
     * 处理登录事件
     * @param msgMap
     * @return
     */
    public String dealLoginAction(Map<String, String> msgMap) {
        StaticLog.info(msgMap.toString(), "INFO");
        String sceneStr = msgMap.get("EventKey");
        if (sceneStr.contains(WeChatConstant.REDIS_KEY_WECHAT_QRCODE_PREFIX)) {

            String openId = msgMap.get("FromUserName");
            redisUtil.set(sceneStr, openId);

            JSONObject userInfo = getUserInfoByOpenId(openId);
            StaticLog.info(userInfo.toString(), "INFO");
            return (String) userInfo.get("nickname");
        }
        return StringUtils.EMPTY;
    }

    /**
     * 登录（通过在redis保存的key查到对应的openId找到用户信息登录）
     *
     * @param sceneStr redis的登录key（value为对应用户的openId）
     * @return
     */
    @Transactional
    public Map<String, Object> loginBySceneStr(String sceneStr) {
        String openId = (String) redisUtil.get(sceneStr);
        if (StringUtils.isBlank(openId)) {
            return null;
        }
        JSONObject userInfo = getUserInfoByOpenId(openId);

        Member member = memberService.selectMemberByOpenId(openId);
        if (null == member) {
            member = new Member();
            member.setName((String) userInfo.get("nickname"));
            member.setOpenId(openId);
            member.setAvatar((String) userInfo.get("headimgurl"));
            memberService.insertMemberByWechatAuth(member);
        }
        String token = jwtUtils.generateToken(member.getId());

        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("expire", jwtUtils.getExpire());
        return map;
    }

}
